/*
 * The MySensors Arduino library handles the wireless radio link and protocol
 * between your home built sensors/actuators and HA controller of choice.
 * The sensors forms a self healing radio network with optional repeaters. Each
 * repeater and gateway builds a routing tables in EEPROM which keeps track of the
 * network topology allowing messages to be routed to nodes.
 *
 * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
 * Copyright (C) 2013-2022 Sensnology AB
 * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
 *
 * Documentation: http://www.mysensors.org
 * Support Forum: http://forum.mysensors.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 */

/**
 * @file MyMessage.h
 *
 * @brief API and type declarations for MySensors messages
 * @defgroup MyMessagegrp MyMessage
 * @ingroup publics
 * @{
 *
 * @brief Here you can find all message types used by the MySensors protocol as well as macros for
 * parsing and manipulating messages.
 */
#ifndef MyMessage_h
#define MyMessage_h

#ifdef __cplusplus
#include <Arduino.h>
#include <stdint.h>
#endif

#define V2_MYS_HEADER_PROTOCOL_VERSION      (2u) //!< Protocol version
#define V2_MYS_HEADER_SIZE                  (7u) //!< Header size
#define V2_MYS_HEADER_MAX_MESSAGE_SIZE      (32u) //!< Max payload size

#define V2_MYS_HEADER_VSL_VERSION_POS       (0) //!< bitfield position version
#define V2_MYS_HEADER_VSL_VERSION_SIZE      (2u) //!< size version field
#define V2_MYS_HEADER_VSL_SIGNED_POS        (2u) //!< bitfield position signed field
#define V2_MYS_HEADER_VSL_SIGNED_SIZE       (1u) //!< size signed field
#define V2_MYS_HEADER_VSL_LENGTH_POS        (3u) //!< bitfield position length field
#define V2_MYS_HEADER_VSL_LENGTH_SIZE       (5u) //!< size length field

#define V2_MYS_HEADER_CEP_COMMAND_POS       (0) //!< bitfield position command field
#define V2_MYS_HEADER_CEP_COMMAND_SIZE      (3u) //!< size command field
#define V2_MYS_HEADER_CEP_ECHOREQUEST_POS   (3u) //!< bitfield position echo request field
#define V2_MYS_HEADER_CEP_ECHOREQUEST_SIZE   (1u) //!< size echo request field
#define V2_MYS_HEADER_CEP_ECHO_POS          (4u) //!< bitfield position echo field
#define V2_MYS_HEADER_CEP_ECHO_SIZE         (1u) //!< size echo field
#define V2_MYS_HEADER_CEP_PAYLOADTYPE_POS   (5u) //!< bitfield position payload type field
#define V2_MYS_HEADER_CEP_PAYLOADTYPE_SIZE  (3u) //!< size payload type field

#define MAX_MESSAGE_SIZE                    V2_MYS_HEADER_MAX_MESSAGE_SIZE	//!< The maximum size of a message (including header)
#define HEADER_SIZE                         V2_MYS_HEADER_SIZE	//!< The size of the header
#define MAX_PAYLOAD_SIZE                    (MAX_MESSAGE_SIZE - HEADER_SIZE) //!< The maximum size of a payload depends on #MAX_MESSAGE_SIZE and #HEADER_SIZE

// deprecated in 3.0.0
#define MAX_PAYLOAD                         MAX_PAYLOAD_SIZE //!< \deprecated in 3.0.0 The maximum size of a payload depends on #MAX_MESSAGE_SIZE and #HEADER_SIZE

/// @brief The command field (message-type) defines the overall properties of a message
typedef enum {
	C_PRESENTATION = 0,	//!< Sent by a node when they present attached sensors. This is usually done in presentation() at startup.
	C_SET          = 1,	//!< This message is sent from or to a sensor when a sensor value should be updated.
	C_REQ          = 2,	//!< Requests a variable value (usually from an actuator destined for controller).
	C_INTERNAL     = 3,	//!< Internal MySensors messages (also include common messages provided/generated by the library).
	C_STREAM       = 4,	//!< For firmware and other larger chunks of data that need to be divided into pieces.
	C_RESERVED_5   = 5,	//!< C_RESERVED_5
	C_RESERVED_6   = 6,	//!< C_RESERVED_6
	C_INVALID_7    = 7	//!< C_INVALID_7
} mysensors_command_t;

#if !DOXYGEN // Hide until we migrate
/// @brief Type of sensor (used when presenting sensors)
typedef enum {
	S_DOOR					= 0,	//!< Door sensor, V_TRIPPED, V_ARMED
	S_MOTION				= 1,	//!< Motion sensor, V_TRIPPED, V_ARMED
	S_SMOKE					= 2,	//!< Smoke sensor, V_TRIPPED, V_ARMED
	S_BINARY				= 3,	//!< Binary light or relay, V_STATUS, V_WATT
	S_LIGHT					= 3,	//!< \deprecated Same as S_BINARY
	S_DIMMER				= 4,	//!< Dimmable light or fan device, V_STATUS (on/off), V_PERCENTAGE (dimmer level 0-100), V_WATT
	S_COVER					= 5,	//!< Blinds or window cover, V_UP, V_DOWN, V_STOP, V_PERCENTAGE (open/close to a percentage)
	S_TEMP					= 6,	//!< Temperature sensor, V_TEMP
	S_HUM					= 7,	//!< Humidity sensor, V_HUM
	S_BARO					= 8,	//!< Barometer sensor, V_PRESSURE, V_FORECAST
	S_WIND					= 9,	//!< Wind sensor, V_WIND, V_GUST
	S_RAIN					= 10,	//!< Rain sensor, V_RAIN, V_RAINRATE
	S_UV					= 11,	//!< Uv sensor, V_UV
	S_WEIGHT				= 12,	//!< Personal scale sensor, V_WEIGHT, V_IMPEDANCE
	S_POWER					= 13,	//!< Power meter, V_WATT, V_KWH, V_VAR, V_VA, V_POWER_FACTOR
	S_HEATER				= 14,	//!< Header device, V_HVAC_SETPOINT_HEAT, V_HVAC_FLOW_STATE, V_TEMP
	S_DISTANCE				= 15,	//!< Distance sensor, V_DISTANCE
	S_LIGHT_LEVEL			= 16,	//!< Light level sensor, V_LIGHT_LEVEL (uncalibrated in percentage),  V_LEVEL (light level in lux)
	S_ARDUINO_NODE			= 17,	//!< Used (internally) for presenting a non-repeating Arduino node
	S_ARDUINO_REPEATER_NODE	= 18,	//!< Used (internally) for presenting a repeating Arduino node
	S_LOCK					= 19,	//!< Lock device, V_LOCK_STATUS
	S_IR					= 20,	//!< IR device, V_IR_SEND, V_IR_RECEIVE
	S_WATER					= 21,	//!< Water meter, V_FLOW, V_VOLUME
	S_AIR_QUALITY			= 22,	//!< Air quality sensor, V_LEVEL
	S_CUSTOM				= 23,	//!< Custom sensor
	S_DUST					= 24,	//!< Dust sensor, V_LEVEL
	S_SCENE_CONTROLLER		= 25,	//!< Scene controller device, V_SCENE_ON, V_SCENE_OFF.
	S_RGB_LIGHT				= 26,	//!< RGB light. Send color component data using V_RGB. Also supports V_WATT
	S_RGBW_LIGHT			= 27,	//!< RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT
	S_COLOR_SENSOR			= 28,	//!< Color sensor, send color information using V_RGB
	S_HVAC					= 29,	//!< Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT, V_HVAC_SETPOINT_COLD, V_HVAC_FLOW_STATE, V_HVAC_FLOW_MODE, V_TEMP
	S_MULTIMETER			= 30,	//!< Multimeter device, V_VOLTAGE, V_CURRENT, V_IMPEDANCE
	S_SPRINKLER				= 31,	//!< Sprinkler, V_STATUS (turn on/off), V_TRIPPED (if fire detecting device)
	S_WATER_LEAK			= 32,	//!< Water leak sensor, V_TRIPPED, V_ARMED
	S_SOUND					= 33,	//!< Sound sensor, V_TRIPPED, V_ARMED, V_LEVEL (sound level in dB)
	S_VIBRATION				= 34,	//!< Vibration sensor, V_TRIPPED, V_ARMED, V_LEVEL (vibration in Hz)
	S_MOISTURE				= 35,	//!< Moisture sensor, V_TRIPPED, V_ARMED, V_LEVEL (water content or moisture in percentage?)
	S_INFO					= 36,	//!< LCD text device / Simple information device on controller, V_TEXT
	S_GAS					= 37,	//!< Gas meter, V_FLOW, V_VOLUME
	S_GPS					= 38,	//!< GPS Sensor, V_POSITION
	S_WATER_QUALITY			= 39	//!< V_TEMP, V_PH, V_ORP, V_EC, V_STATUS
} mysensors_sensor_t;

/// @brief Type of sensor data (for set/req/echo messages)
typedef enum {
	V_TEMP					= 0,	//!< S_TEMP. Temperature S_TEMP, S_HEATER, S_HVAC
	V_HUM					= 1,	//!< S_HUM. Humidity
	V_STATUS				= 2,	//!< S_BINARY, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. Used for setting/reporting binary (on/off) status. 1=on, 0=off
	V_LIGHT					= 2,	//!< \deprecated Same as V_STATUS
	V_PERCENTAGE			= 3,	//!< S_DIMMER. Used for sending a percentage value 0-100 (%).
	V_DIMMER				= 3,	//!< \deprecated Same as V_PERCENTAGE
	V_PRESSURE				= 4,	//!< S_BARO. Atmospheric Pressure
	V_FORECAST				= 5,	//!< S_BARO. Whether forecast. string of "stable", "sunny", "cloudy", "unstable", "thunderstorm" or "unknown"
	V_RAIN					= 6,	//!< S_RAIN. Amount of rain
	V_RAINRATE				= 7,	//!< S_RAIN. Rate of rain
	V_WIND					= 8,	//!< S_WIND. Wind speed
	V_GUST					= 9,	//!< S_WIND. Gust
	V_DIRECTION				= 10,	//!< S_WIND. Wind direction 0-360 (degrees)
	V_UV					= 11,	//!< S_UV. UV light level
	V_WEIGHT				= 12,	//!< S_WEIGHT. Weight(for scales etc)
	V_DISTANCE				= 13,	//!< S_DISTANCE. Distance
	V_IMPEDANCE				= 14,	//!< S_MULTIMETER, S_WEIGHT. Impedance value
	V_ARMED					= 15,	//!< S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER. Armed status of a security sensor. 1 = Armed, 0 = Bypassed
	V_TRIPPED				= 16,	//!< S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER, S_WATER_LEAK, S_SOUND, S_VIBRATION, S_MOISTURE. Tripped status of a security sensor. 1 = Tripped, 0
	V_WATT					= 17,	//!< S_POWER, S_BINARY, S_DIMMER, S_RGB_LIGHT, S_RGBW_LIGHT. Watt value for power meters
	V_KWH					= 18,	//!< S_POWER. Accumulated number of KWH for a power meter
	V_SCENE_ON				= 19,	//!< S_SCENE_CONTROLLER. Turn on a scene
	V_SCENE_OFF				= 20,	//!< S_SCENE_CONTROLLER. Turn of a scene
	V_HVAC_FLOW_STATE		= 21,	//!< S_HEATER, S_HVAC. HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver")
	V_HEATER				= 21,	//!< \deprecated Same as V_HVAC_FLOW_STATE
	V_HVAC_SPEED			= 22,	//!< S_HVAC, S_HEATER. HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto")
	V_LIGHT_LEVEL			= 23,	//!< S_LIGHT_LEVEL. Uncalibrated light level. 0-100%. Use V_LEVEL for light level in lux
	V_VAR1					= 24,	//!< VAR1
	V_VAR2					= 25,	//!< VAR2
	V_VAR3					= 26,	//!< VAR3
	V_VAR4					= 27,	//!< VAR4
	V_VAR5					= 28,	//!< VAR5
	V_UP					= 29,	//!< S_COVER. Window covering. Up
	V_DOWN					= 30,	//!< S_COVER. Window covering. Down
	V_STOP					= 31,	//!< S_COVER. Window covering. Stop
	V_IR_SEND				= 32,	//!< S_IR. Send out an IR-command
	V_IR_RECEIVE			= 33,	//!< S_IR. This message contains a received IR-command
	V_FLOW					= 34,	//!< S_WATER. Flow of water (in meter)
	V_VOLUME				= 35,	//!< S_WATER. Water volume
	V_LOCK_STATUS			= 36,	//!< S_LOCK. Set or get lock status. 1=Locked, 0=Unlocked
	V_LEVEL					= 37,	//!< S_DUST, S_AIR_QUALITY, S_SOUND (dB), S_VIBRATION (hz), S_LIGHT_LEVEL (lux)
	V_VOLTAGE				= 38,	//!< S_MULTIMETER
	V_CURRENT				= 39,	//!< S_MULTIMETER
	V_RGB					= 40,	//!< S_RGB_LIGHT, S_COLOR_SENSOR. Sent as ASCII hex: RRGGBB (RR=red, GG=green, BB=blue component)
	V_RGBW					= 41,	//!< S_RGBW_LIGHT. Sent as ASCII hex: RRGGBBWW (WW=white component)
	V_ID					= 42,	//!< Used for sending in sensors hardware ids (i.e. OneWire DS1820b).
	V_UNIT_PREFIX			= 43,	//!< Allows sensors to send in a string representing the unit prefix to be displayed in GUI, not parsed by controller! E.g. cm, m, km, inch.
	V_HVAC_SETPOINT_COOL	= 44,	//!< S_HVAC. HVAC cool setpoint (Integer between 0-100)
	V_HVAC_SETPOINT_HEAT	= 45,	//!< S_HEATER, S_HVAC. HVAC/Heater setpoint (Integer between 0-100)
	V_HVAC_FLOW_MODE		= 46,	//!< S_HVAC. Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn")
	V_TEXT					= 47,	//!< S_INFO. Text message to display on LCD or controller device
	V_CUSTOM				= 48,	//!< Custom messages used for controller/inter node specific commands, preferably using S_CUSTOM device type.
	V_POSITION				= 49,	//!< GPS position and altitude. Payload: latitude;longitude;altitude(m). E.g. "55.722526;13.017972;18"
	V_IR_RECORD				= 50,	//!< Record IR codes S_IR for playback
	V_PH					= 51,	//!< S_WATER_QUALITY, water PH
	V_ORP					= 52,	//!< S_WATER_QUALITY, water ORP : redox potential in mV
	V_EC					= 53,	//!< S_WATER_QUALITY, water electric conductivity μS/cm (microSiemens/cm)
	V_VAR					= 54,	//!< S_POWER, Reactive power: volt-ampere reactive (var)
	V_VA					= 55,	//!< S_POWER, Apparent power: volt-ampere (VA)
	V_POWER_FACTOR			= 56,	//!< S_POWER, Ratio of real power to apparent power: floating point value in the range [-1,..,1]
	V_MULTI_MESSAGE			= 57,	//!< Special type, multiple sensors in one message
} mysensors_data_t;
#endif

/// @brief Type of internal messages (for internal messages)
typedef enum {
	I_BATTERY_LEVEL				= 0,	//!< Battery level
	I_TIME						= 1,	//!< Time (request/response)
	I_VERSION					= 2,	//!< Version
	I_ID_REQUEST				= 3,	//!< ID request
	I_ID_RESPONSE				= 4,	//!< ID response
	I_INCLUSION_MODE			= 5,	//!< Inclusion mode
	I_CONFIG					= 6,	//!< Config (request/response)
	I_FIND_PARENT_REQUEST		= 7,	//!< Find parent
	I_FIND_PARENT_RESPONSE		= 8,	//!< Find parent response
	I_LOG_MESSAGE				= 9,	//!< Log message
	I_CHILDREN					= 10,	//!< Children
	I_SKETCH_NAME				= 11,	//!< Sketch name
	I_SKETCH_VERSION			= 12,	//!< Sketch version
	I_REBOOT					= 13,	//!< Reboot request
	I_GATEWAY_READY				= 14,	//!< Gateway ready
	I_SIGNING_PRESENTATION		= 15,	//!< Provides signing related preferences (first byte is preference version)
	I_NONCE_REQUEST				= 16,	//!< Request for a nonce
	I_NONCE_RESPONSE			= 17,	//!< Payload is nonce data
	I_HEARTBEAT_REQUEST			= 18,	//!< Heartbeat request
	I_PRESENTATION				= 19,	//!< Presentation message
	I_DISCOVER_REQUEST			= 20,	//!< Discover request
	I_DISCOVER_RESPONSE			= 21,	//!< Discover response
	I_HEARTBEAT_RESPONSE		= 22,	//!< Heartbeat response
	I_LOCKED					= 23,	//!< Node is locked (reason in string-payload)
	I_PING						= 24,	//!< Ping sent to node, payload incremental hop counter
	I_PONG						= 25,	//!< In return to ping, sent back to sender, payload incremental hop counter
	I_REGISTRATION_REQUEST		= 26,	//!< Register request to GW
	I_REGISTRATION_RESPONSE		= 27,	//!< Register response from GW
	I_DEBUG						= 28,	//!< Debug message
	I_SIGNAL_REPORT_REQUEST		= 29,	//!< Device signal strength request
	I_SIGNAL_REPORT_REVERSE		= 30,	//!< Internal
	I_SIGNAL_REPORT_RESPONSE	= 31,	//!< Device signal strength response (RSSI)
	I_PRE_SLEEP_NOTIFICATION	= 32,	//!< Message sent before node is going to sleep
	I_POST_SLEEP_NOTIFICATION	= 33	//!< Message sent after node woke up (if enabled)
} mysensors_internal_t;

/// @brief Type of data stream (for streamed message)
typedef enum {
	ST_FIRMWARE_CONFIG_REQUEST	= 0,	//!< Request new FW, payload contains current FW details
	ST_FIRMWARE_CONFIG_RESPONSE	= 1,	//!< New FW details to initiate OTA FW update
	ST_FIRMWARE_REQUEST			= 2,	//!< Request FW block
	ST_FIRMWARE_RESPONSE		= 3,	//!< Response FW block
	ST_SOUND					= 4,	//!< Sound
	ST_IMAGE					= 5,	//!< Image
	ST_FIRMWARE_CONFIRM	= 6, //!< Mark running firmware as valid (MyOTAFirmwareUpdateNVM + mcuboot)
	ST_FIRMWARE_RESPONSE_RLE = 7,	//!< Response FW block with run length encoded data
} mysensors_stream_t;

/// @brief Type of payload
typedef enum {
	P_STRING				= 0,	//!< Payload type is string
	P_BYTE					= 1,	//!< Payload type is byte
	P_INT16					= 2,	//!< Payload type is INT16
	P_UINT16				= 3,	//!< Payload type is UINT16
	P_LONG32				= 4,	//!< Payload type is INT32
	P_ULONG32				= 5,	//!< Payload type is UINT32
	P_CUSTOM				= 6,	//!< Payload type is binary
	P_FLOAT32				= 7		//!< Payload type is float32
} mysensors_payload_t;


#ifndef BIT
#define BIT(n)                  ( 1<<(n) ) //!< Bit indexing macro
#endif
#define BIT_MASK(len)           ( BIT(len)-1 ) //!< Create a bitmask of length 'len'
#define BF_MASK(start, len)     ( BIT_MASK(len)<<(start) ) //!< Create a bitfield mask of length starting at bit 'start'

#define BF_PREP(x, start, len)  ( ((x)&BIT_MASK(len)) << (start) ) //!< Prepare a bitmask for insertion or combining
#define BF_GET(y, start, len)   ( ((y)>>(start)) & BIT_MASK(len) ) //!< Extract a bitfield of length 'len' starting at bit 'start' from 'y'
#define BF_SET(y, x, start, len)    ( y= ((y) &~ BF_MASK(start, len)) | BF_PREP(x, start, len) ) //!< Insert a new bitfield value 'x' into 'y'

// Getters/setters for special bit fields in header
// deprecated in 3.0.0
#define mSetVersion(_message, _version) _message.setVersion(_version) //!< \deprecated Set version field
#define mGetVersion(_message) _message.getVersion() //!< \deprecated Get version field

#define mSetSigned(_message, _signed) _message.setSigned(_signed) //!< \deprecated Set signed field
#define mGetSigned(_message) _message.getSigned() //!< \deprecated Get signed field

#define mSetLength(_message,_length) _message.setLength(_length) //!< \deprecated Set length field
#define mGetLength(_message) _message.getLength() //!< \deprecated Get length field

#define mSetCommand(_message, _command) _message.setCommand(_command) //!< \deprecated Set command field
#define mGetCommand(_message) _message.getCommand() //!< \deprecated Get command field

#define mSetRequestEcho(_message, _requestEcho) _message.setRequestEcho(_requestEcho) //!< \deprecated Set echo request field
#define mGetRequestEcho(_message) _message.getRequestEcho() //!< \deprecated Get echo request field

#define mSetEcho(_message, _echo) _message.setEcho(_echo) //!< \deprecated Set echo field
#define mGetEcho(_message) _message.getEcho() //!< \deprecated Get echo field

#define mSetPayloadType(_message, _payloadType) _message.setPayloadType(_payloadType) //!< \deprecated Set payload type field
#define mGetPayloadType(_message) _message.getPayloadType() //!< \deprecated Get payload type field

#if defined(__cplusplus) || defined(DOXYGEN)
/**
 * @brief MyMessage is used to create, manipulate, send and read MySensors messages
 */
class MyMessage
{
private:
	char* getCustomString(char *buffer) const;

public:

	/**
	 * Default constructor
	 */
	MyMessage(void);

	/**
	 * Constructor
	 * @param sensorId id of the child sensor for this message
	 * @param dataType
	 */
	MyMessage(const uint8_t sensorId, const mysensors_data_t dataType);

	/**
	 * @brief Clear message contents.
	 */
	void clear(void);

	/**
	 * If payload is something else than P_STRING you can have the payload value converted
	 * into string representation by supplying a buffer with the minimum size of
	 * 2 * MAX_PAYLOAD_SIZE + 1. This is to be able to fit hex-conversion of a full binary payload.
	 * @param buffer pointer to a buffer that's at least 2 * MAX_PAYLOAD_SIZE + 1 bytes large
	 */
	char* getStream(char *buffer) const;

	/**
	 * @brief Copy the payload into the supplied buffer
	 */
	char* getString(char *buffer) const;

	/**
	 * @brief Get payload as string
	 * @return pointer to a char array storing the string
	 */
	const char* getString(void) const;

	/**
	 * @brief Get custom payload
	 * @return pointer to the raw payload
	 */
	void* getCustom(void) const;

	/**
	 * @brief Get bool payload
	 * @return a bool with the value of the payload (true/false)
	 */
	bool getBool(void) const;

	/**
	 * @brief Get unsigned 8-bit integer payload
	 * @return the value of the payload, 0 to 255
	 */
	uint8_t getByte(void) const;

	/**
	 * @brief Get float payload
	 * @return the floating-point value of the payload
	 */
	float getFloat(void) const;

	/**
	 * @brief Get signed 16-bit integer payload
	 * @return the value of the payload, –32768 to 32767
	 */
	int16_t getInt(void) const;

	/**
	 * @brief Get unsigned 16-bit integer payload
	 * @return the value of the payload, 0 to 65535
	 */
	uint16_t getUInt(void) const;

	/**
	 * @brief Get signed 32-bit integer payload
	 * @return the value of the payload, –2147483648 to 2147483647
	 */
	int32_t getLong(void) const;

	/**
	 * @brief Get unsigned 32-bit integer payload
	 * @return the value of the payload, 0 to 4294967295
	 */
	uint32_t getULong(void) const;

	/**
	* @brief getHeaderSize
	* @return the size of the header
	*/
	uint8_t getHeaderSize(void) const;

	/**
	* @brief getMaxPayloadSize
	* @return the max. size of the payload
	*/
	uint8_t getMaxPayloadSize(void) const;

	/**
	* @brief getExpectedMessageSize
	* @return the expected message size based on header information
	*/
	uint8_t getExpectedMessageSize(void) const;

	/**
	* @brief isProtocolVersionValid
	* @return true if the protocol version is valid
	*/
	bool isProtocolVersionValid(void) const;

	/**
	 * @brief Getter for echo request
	 * @return echo request
	 */
	bool getRequestEcho(void) const;

	/**
	 * @brief Setter for echo request
	 * @param requestEcho
	 */
	MyMessage& setRequestEcho(const bool requestEcho);

	/**
	 * @brief Getter for version
	 * @return version
	 */
	uint8_t getVersion(void) const;

	/**
	 * @brief Setter for version
	 */
	MyMessage& setVersion(void);

	/**
	* @brief Getter for length
	* @return length
	*/
	uint8_t getLength(void) const;

	/**
	 * @brief Setter for length
	 * @param length
	 */
	MyMessage& setLength(const uint8_t length);

	/**
	* @brief Getter for command type
	* @return #mysensors_command_t
	*/
	mysensors_command_t getCommand(void) const;

	/**
	 * @brief Setter for command type
	 * @param command
	 */
	MyMessage& setCommand(const mysensors_command_t command);

	/**
	* @brief Getter for payload type
	* @return payload type
	*/
	mysensors_payload_t getPayloadType(void) const;

	/**
	 * @brief Setter for payload type
	 * @param payloadType
	 */
	MyMessage& setPayloadType(const mysensors_payload_t payloadType);

	/**
	* @brief Getter for sign field
	* @return sign field
	*/
	bool getSigned(void) const;

	/**
	 * @brief Setter for sign field
	 * @param signedFlag
	 */
	MyMessage& setSigned(const bool signedFlag);

	/**
	 * \deprecated use isEcho()
	 * @brief Getter for echo-flag.
	 * @return true if this is an echoed message
	 */
	bool isAck(void) const;

	/**
	 * @brief Getter for echo-flag.
	 * @return true if this is an echoed message
	 */
	bool isEcho(void) const;

	/**
	* @brief Setter for echo-flag.
	* @param echo true if this an echo message
	*/
	MyMessage& setEcho(const bool echo);

	/**
	 * @brief Get message type
	 * @return messageType
	 */
	uint8_t getType(void) const;

	/**
	 * @brief Set message type
	 * @param messageType
	 */
	MyMessage& setType(const uint8_t messageType);

	/**
	* @brief Get last ID
	* @return lastId
	*/
	uint8_t getLast(void) const;

	/**
	 * @brief Set last ID
	 * @param lastId
	 */
	MyMessage& setLast(const uint8_t lastId);

	/**
	* @brief Get sender ID
	* @return sender
	*/
	uint8_t getSender(void) const;

	/**
	 * @brief Set sender ID
	 * @param senderId
	 */
	MyMessage& setSender(const uint8_t senderId);

	/**
	 * @brief Get sensor ID of message
	 * @return sensorId
	 */
	uint8_t getSensor(void) const;

	/**
	 * @brief Set which child sensor this message belongs to
	 * @param sensorId
	 */
	MyMessage& setSensor(const uint8_t sensorId);

	/**
	 * @brief Get destination
	 * @return destinationId
	 */
	uint8_t getDestination(void) const;

	/**
	 * @brief Set final destination node id for this message
	 * @param destinationId
	 */
	MyMessage& setDestination(const uint8_t destinationId);

	/**
	 * @brief Set entire payload
	 * @param payload pointer to the buffer where the payload is stored
	 * @param length of the payload
	 */
	MyMessage& set(const void* payload, const size_t length);

	/**
	 * @brief Set payload to character array
	 * @param value pointer to the character array. The array must be null-terminated.
	 */
	MyMessage& set(const char* value);
#if !defined(__linux__)
	/**
	 * @brief Set payload to character array from flash
	 * @param value pointer to the character array. The array must be null-terminated.
	 */
	MyMessage& set(const __FlashStringHelper* value);
#endif

	/**
	 * @brief Set payload to decimal number
	 * @param value float
	 * @param decimals number of decimals to include
	 */
	MyMessage& set(const float value, const uint8_t decimals);

	/**
	 * @brief Set payload to bool value
	 * @param value true or false
	 */
	MyMessage& set(const bool value);

	/**
	 * @brief Set payload to unsigned 8-bit integer value
	 * @param value (0 to 255)
	 */
	MyMessage& set(const uint8_t value);

	/**
	 * @brief Set payload to unsigned 32-bit integer value
	 * @param value (0 to 4294967295)
	 */
	MyMessage& set(const uint32_t value);

	/**
	 * @brief Set payload to signed 32-bit integer value
	 * @param value (–2147483648 to 2147483647)
	 */
	MyMessage& set(const int32_t value);

	/**
	 * @brief Set payload to unsigned 16-bit integer value
	 * @param value (0 to 65535)
	 */
	MyMessage& set(const uint16_t value);

	/**
	 * @brief Set payload to signed 16-bit integer value
	 * @param value (–32768 to 32767)
	 */
	MyMessage& set(const int16_t value);

#else

typedef union {
	struct {

#endif
	uint8_t last;							//!< 8 bit - Id of last node this message passed
	uint8_t sender;						//!< 8 bit - Id of sender node (origin)
	uint8_t destination;			//!< 8 bit - Id of destination node

	/**
	 * 2 bit - Protocol version<br>
	 * 1 bit - Signed flag<br>
	 * 5 bit - Length of payload
	 */
	uint8_t version_length;

	/**
	 * 3 bit - Command type<br>
	 * 1 bit - Request an echo - Indicator that receiver should echo the message back to the sender<br>
	 * 1 bit - Is echo message - Indicator that this is the echoed message<br>
	 * 3 bit - Payload data type
	 */
	uint8_t command_echo_payload;

	uint8_t type; //!< 8 bit - Type varies depending on command
	uint8_t sensor; //!< 8 bit - Id of sensor that this message concerns.

	/*
	 * Each message can transfer a payload. We add one extra byte for string
	 * terminator \0 to be "printable" this is not transferred OTA
	 * This union is used to simplify the construction of the binary data types transferred.
	 */
	union {
		uint8_t bValue; //!< unsigned byte value (8-bit)
		uint16_t uiValue; //!< unsigned integer value (16-bit)
		int16_t iValue; //!< signed integer value (16-bit)
		uint32_t ulValue; //!< unsigned long value (32-bit)
		int32_t lValue; //!< signed long value (32-bit)
		struct { //!< Float messages
			float fValue;
			uint8_t fPrecision; //!< Number of decimals when serializing
		};
		char data[MAX_PAYLOAD_SIZE + 1]; //!< Buffer for raw payload data
	} __attribute__((packed)); //!< Doxygen will complain without this comment
#if defined(__cplusplus) || defined(DOXYGEN)
} __attribute__((packed));
#else
};
uint8_t array[HEADER_SIZE + MAX_PAYLOAD_SIZE + 1]; //!< buffer for entire message
} __attribute__((packed)) MyMessage;
#endif

#endif
/** @}*/
